#ifndef TOOL_HPP
#define TOOL_HPP

#include "AnalysisLogic.hpp"
#include "store/struct/DurationCarrier.hpp"
#include "store/struct/LadderLineCarrier.hpp"
#include "store/struct/Basic.hpp" // 包含 Rhythm 结构体定义
#include "TimeHelper.hpp"
#include <QString>
#include <QDebug>
#include <QDateTime>
#include <QDir>
#include <QCommandLineParser>
#include <QApplication>
#include <numeric>
#include <regex>
#include "config.h"

/**
 * @brief 工具类 Tool，封装分析相关的功能
 */
class Tool {
public:

    /**
     * @brief 获取和设置 IMPORTANALYSIS 路径
     *
     * @param app QApplication 对象，用于解析命令行参数
     * @return QString 当前的 IMPORTANALYSIS 路径
     */
    static QString analysisParser(QApplication& app) {
        // 设置命令行解析器
        QCommandLineParser parser;
        parser.setApplicationDescription("节拍管理应用程序");
        parser.addHelpOption();

        // 定义路径选项
        QCommandLineOption pathOption(QStringList() << "p" << "path",
                                      "设置 IMPORTANALYSIS 路径",
                                      "path");
        parser.addOption(pathOption);

        // 解析命令行参数
        parser.process(app);

        // 定义变量用于存储最终的路径
        if (parser.isSet(pathOption)) {
            getImportAnalysisPath() = parser.value(pathOption);
            qDebug() << "Import Analysis Path overridden to:" << getImportAnalysisPath();
        } else {
            qDebug() << "Using default Import Analysis Path:" << getImportAnalysisPath();
        }

        return getImportAnalysisPath();
    }


    /**
     * @brief 导入文件夹并解析 XML，返回合并后的数据列表
     *
     * @param baseDirPath 文件路径 (BeatEditor目录)
     * @return QList<MergeToAll> 合并后的数据列表
     */
    static Basic ImportXML(const QString &baseDirPath, const QString &dateStr = QString()) {
        return AnalysisLogic::ImportXML(getImportAnalysisPath(), dateStr);
    }

    /**
     * @brief 通用查询函数，筛选并分组 Rhythms
     * @param rhythms 传入的 Rhythm 列表
     * @param startTime 查询的开始时间（可选，默认为无效时间）
     * @param endTime 查询的结束时间（可选，默认为无效时间）
     * @return 分组后的节点及其持续时间列表
     */
    static QList<DurationCarrier> queryRhythmToDurationCarrier (const QList<Rhythm> &rhythms, const QDateTime &startDateTime = QDateTime(), const QDateTime &endDateTime = QDateTime()) {
        return queryRhythms(rhythms, startDateTime, endDateTime);
    }

    /**
     * @brief 通用查询函数，筛选并分组 Scatter
     * @param rhythms 传入的 Scatter 列表
     * @param startTime 查询的开始时间（可选，默认为无效时间）
     * @param endTime 查询的结束时间（可选，默认为无效时间）
     * @return 分组后的散点列表
     */
    static QList<LadderLineCarrier> queryLadderLineToLadderLineCarrier (const QList<LadderLine> &ladderLines, const QDateTime &startDateTime = QDateTime(), const QDateTime &endDateTime = QDateTime()) {
        return queryLadderLine(ladderLines, startDateTime, endDateTime);
    }


private:
    /**
     * @brief 获取和设置 IMPORTANALYSIS 路径的内部函数
     *
     * @return QString& 引用类型，允许修改路径
     */
    static QString& getImportAnalysisPath() {
        static QString importAnalysisPath = IMPORTANALYSIS;
        return importAnalysisPath;
    }

    /**
    * @brief 将时间字符串解析为 QDateTime 对象
    *
    * @param timeStr 要解析的时间字符串，例如 "14:30:15.123"
    * @param format 时间字符串的格式，默认为 "hh:mm:ss.zzz"
    * @param date 要与时间组合的日期，默认为当前日期 QDate::currentDate()
    * @return QDateTime 成功解析后的 QDateTime 对象，如果解析失败，则返回使用默认时间组合的 QDateTime
    */
    static QDateTime stringToDateTime( const QString& timeStr, const QString& format = "hh:mm:ss.zzz", const QDate& date = QDate::currentDate()) {
        // 解析时间字符串
        QTime time = QTime::fromString(timeStr, format);

        // 检查时间是否有效
        if (!time.isValid()) {
            qWarning() << "时间格式无效:" << timeStr << "，使用默认时间: 00:00:00.000";
            // 使用默认时间 "00:00:00.000"
            time = QTime::fromString("00:00:00.000", "hh:mm:ss.zzz");
        }

        // 组合日期和时间
        QDateTime dateTime(date, time);
        qDebug() << dateTime;
        return dateTime;
    }

    /**
     * @brief 通用查询函数，直接将传入的 Rhythm 列表分组并转换成 DurationCarrier 列表
     * @param rhythms 传入的 Rhythm 列表
     * @return 分组后的节点及其持续时间列表
     */
    static QList<DurationCarrier> queryRhythms(const QList<Rhythm> &rhythms,
            const QDateTime &startDateTime = QDateTime(),
            const QDateTime &endDateTime   = QDateTime()) {
        // 目标结构
        QList<DurationCarrier> result;

        if (rhythms.isEmpty()) {
            return result;
        }

        // 先给 rhythms 排序，比如先按 node 排序
        QList<Rhythm> sortedRhythms = rhythms;
        std::sort(sortedRhythms.begin(), sortedRhythms.end(), [](const Rhythm &a, const Rhythm &b) {
            // 需要按 folder 再按 node，或者只按 node，视业务需求调整
            // return a.node < b.node;
            // 这里我示例先按 folder，再按 node 排序
            if (a.folder == b.folder) {
                return a.node < b.node;
            }
            return a.folder < b.folder;
        });

        // QMap 分组:
        // QMap<folder, QMap<node, QList<double>>>
        QMap<QString, QMap<QString, QList<double>>> groupedData;

        bool filterByTime = startDateTime.isValid() && endDateTime.isValid();

        for (const Rhythm &rhythm : sortedRhythms) {
            if (filterByTime) {
                bool withinRange = isTimeWithinRange(startDateTime, endDateTime,
                                                     rhythm.startTime, rhythm.endTime);
                if (!withinRange) {
                    continue; // 不在范围内就忽略
                }
            }

            // 注意，这里假设 rhythm.folder 是一个数字，需要转成字符串。
            // 如果本身就是字符串，可直接用 rhythm.folder
            QString folderStr = QString::number(rhythm.folder);

            // 进行两级分组
            groupedData[folderStr][rhythm.node].append(rhythm.duration);
        }

        // 对 groupedData 做排序并转换 => sortComplexGroupedData(...) 假设它返回
        // QList<QPair<folder, QList<QPair<node, QList<double>>>>>
        QList<QPair<QString, QList<QPair<QString, QList<double>>>>> sortedData = sortComplexGroupedData(groupedData);

        // 把 sortedData 转成 QList<DurationCarrier>
        int index = 0;
        for (auto &folderPair : sortedData) {
            QString folder                                = folderPair.first;
            QList<QPair<QString, QList<double>>> nodeList = folderPair.second;

            DurationCarrier carrier(folder, nodeList);
            result.append(carrier);

            ++index; // 增加索引
        }

        /**
            是获取4个文件夹 时合并使用 直接返回 result只获取两个文件夹使用，因为只需要 当前和上一次的
        */
        // for (const DurationCarrier &carrier : mergeNodeDurations(result)) {
        //     qDebug() << carrier.toJson();
        // }

        return result;
    }



    /**
    * @brief 通用查询函数，直接将传入的 Scatter 列表分组并转换成 LadderLineCarrier 列表
    * @param scatters 传入的 Scatter 列表
    * @return 分组后的散点列表
    */
    static QList<LadderLineCarrier> queryLadderLine(const QList<LadderLine> &ladderLines, const QDateTime &startDateTime = QDateTime(), const QDateTime &endDateTime = QDateTime()) {
        QList<LadderLineCarrier> result;

        if (ladderLines.isEmpty()) {
            return result;
        }

        bool filterByTime = startDateTime.isValid() && endDateTime.isValid();

        // 打印 ladderLines（调试用）
        /*
        qDebug() << "---- LadderLines Start ----";
        for (int i = 0; i < ladderLines.size(); ++i) {
            qDebug() << "LadderLine" << i + 1 << ":" << ladderLines.at(i);
        }
        qDebug() << "---- LadderLines End ----";
        */

        // 1. 按照原始顺序进行分组
        QHash<QString, QList<LadderLine>> groupedHash;
        QList<QString> nodeOrder; // 记录节点的顺序

        for (const auto &line : ladderLines) {
            if (!groupedHash.contains(line.node)) {
                nodeOrder.append(line.node); // 记录第一次出现的节点顺序
            }
            groupedHash[line.node].append(line);
        }

        // 2. 将分组结果转换为 LadderLineCarrier 列表，按照 node 的原始顺序
        for (const QString &node : nodeOrder) {
            LadderLineCarrier carrier;
            carrier.seriesName = node;

            // 提取 slotval 并赋值给 dataPoints
            QList<PointTrigger> pointTriggers;
            for (const LadderLine &ll : groupedHash.value(node)) {
                if (filterByTime) {
                    bool withinRange = isTimeWithinRange(startDateTime, endDateTime, ll.triggerTime);
                    // qDebug() << "Rhythm in range:" << withinRange;
                    // qDebug() << "Range:" << startDateTime << "to" << endDateTime
                    //          << "Rhythm Time:" << rhythm.startTime << "to" << rhythm.endTime;

                    if (withinRange) {
                        // 如果在范围内，则添加到 groupedData
                        pointTriggers.append(PointTrigger(ll.slotval, ll.trigger));
                    } else {
                        // 如果不在范围内，根据需求进行处理
                        // 例如，忽略不在范围内的 rhythms，或者进行其他处理
                        // qDebug() << "Rhythm 不在范围内，节点：" << rhythm.node
                        //          << "时长：" << rhythm.duration;
                        // 如果需要实时更新其他数据，可以在这里进行相应操作
                    }
                } else {
                    pointTriggers.append(PointTrigger(ll.slotval, ll.trigger));
                }
            }
            carrier.dataPoints = pointTriggers;

            result.append(carrier);
        }

        // 调试打印结果
        // qDebug() << "---- Grouped LadderLines Start ----";
        // for (int i = 0; i < result.size(); ++i) {
        //     const auto &carrier = result.at(i);
        //     qDebug() << carrier;
        // }
        // qDebug() << "---- Grouped LadderLines End ----";

        return result;
    }


    static QList<DurationCarrier> mergeNodeDurations(const QList<DurationCarrier> &result) {
        QList<DurationCarrier> mergedResult;

        for (const DurationCarrier &carrier : result) {
            QList<QPair<QString, QList<double>>> mergedNodeDurations;
            const QList<QPair<QString, QList<double>>> &currentNodeDurations = carrier.nodeDurations;

            // 按照每两个节点进行合并
            for (int i = 0; i < currentNodeDurations.size(); i += 2) {
                QPair<QString, QList<double>> mergedPair;

                if (i + 1 < currentNodeDurations.size()) {
                    // 合并当前节点和下一个节点
                    QString mergedNode = currentNodeDurations[i].first + currentNodeDurations[i + 1].first;
                    QList<double> mergedDurations = currentNodeDurations[i].second + currentNodeDurations[i + 1].second;

                    mergedPair = qMakePair(mergedNode, mergedDurations);
                } else {
                    // 如果节点数为奇数，最后一个节点不进行合并
                    mergedPair = currentNodeDurations[i];
                }

                mergedNodeDurations.append(mergedPair);
            }

            // 创建新的 DurationCarrier 并添加到结果列表中
            DurationCarrier mergedCarrier(carrier.folder, mergedNodeDurations);
            mergedResult.append(mergedCarrier);
        }

        return mergedResult;
    }


    static QList<QPair<QString, QList<QPair<QString, QList<double>>>>> sortComplexGroupedData(const QMap<QString, QMap<QString, QList<double>>> &groupedData) {
        // 1) 先翻转为 node -> folder -> durations
        QMap<QString, QMap<QString, QList<double>>> nodeCentered;

        for (auto folderIt = groupedData.begin(); folderIt != groupedData.end(); ++folderIt) {
            const QString &folder = folderIt.key();
            const QMap<QString, QList<double>> &nodeMap = folderIt.value();

            // 遍历当前 folder 下的每个 node
            for (auto nodeIt = nodeMap.begin(); nodeIt != nodeMap.end(); ++nodeIt) {
                const QString &node = nodeIt.key();
                const QList<double> &durations = nodeIt.value();

                // 翻转过程： nodeCentered[node][folder] = durations;
                nodeCentered[node][folder] = durations;
            }
        }

        // 2) 把 nodeCentered 转成我们想要返回的结构： QList<QPair<node, QList<QPair<folder, durations>>>>
        QList<QPair<QString, QList<QPair<QString, QList<double>>>>> result;

        // 2.1 先取出所有 node 做排序
        QList<QString> nodeKeys = nodeCentered.keys();

        // 这里演示一下如何用正则提取 "节拍1" 里的数字进行排序
        // 如果你的 node 并不带数字，或者只是简单按字典序，那就可以直接 sort(nodeKeys) 即可。
        std::regex nodeRx("节拍(\\d+)");

        // 用来保存 (nodeName, nodeNumber)
        QList<QPair<QString, int>> nodeNumberPairs;
        for (const auto &n : nodeKeys) {
            std::smatch match;
            std::string ns = n.toStdString();
            int number = 0;
            if (std::regex_search(ns, match, nodeRx) && match.size() > 1) {
                number = std::stoi(match[1]);
            }
            nodeNumberPairs.append(qMakePair(n, number));
        }

        // 按数字升序排
        std::sort(nodeNumberPairs.begin(), nodeNumberPairs.end(),
        [](const QPair<QString, int> &a, const QPair<QString, int> &b) {
            return a.second < b.second;
        });

        // 2.2 依次遍历每个排好序的 node
        for (auto &nodePair : nodeNumberPairs) {
            QString nodeName = nodePair.first;
            // nodeCentered[nodeName] 是一个 QMap<folder, QList<double>>
            auto folderMap = nodeCentered[nodeName];

            // 拿到所有 folder key，并做排序
            QList<QString> folderKeys = folderMap.keys();
            std::sort(folderKeys.begin(), folderKeys.end()); // 简单字典序即可

            // 准备承接 (folder, durations)
            QList<QPair<QString, QList<double>>> folderPairs;
            for (const QString &f : folderKeys) {
                folderPairs.append(qMakePair(f, folderMap[f]));
            }

            // 把 (nodeName, folderPairs) 加入最终 result
            result.append(qMakePair(nodeName, folderPairs));
        }

        return result;
    }


    static QList<QPair<QString, QList<double>>> sortGroupedData(const QMap<QString, QList<double>> &groupedData) {
        // 提取所有键
        QList<QString> keys = groupedData.keys();

        // 使用正则表达式提取数字
        std::regex rx("IO板卡轴(\\d+)节拍");

        // 创建一个包含键和对应数字的列表
        QList<QPair<QString, int>> keyNumberPairs;
        for(const QString &key : keys) {
            std::smatch match;
            std::string keyStd = key.toStdString();
            int number = 0;
            if (std::regex_search(keyStd, match, rx) && match.size() > 1) {
                number = std::stoi(match[1]);
            }
            keyNumberPairs.append(qMakePair(key, number));
        }

        // 按数字排序键
        std::sort(keyNumberPairs.begin(), keyNumberPairs.end(), [](const QPair<QString, int> &a, const QPair<QString, int> &b) -> bool {
            return a.second < b.second;
        });

        // 创建排序后的列表
        QList<QPair<QString, QList<double>>> sortedList;
        QString output;
        for(const auto &pair : keyNumberPairs) {
            sortedList.append(qMakePair(pair.first, groupedData.value(pair.first)));
            output += pair.first + " ";
        }

        // 打印排序后的键
        // qDebug() << "排序后的结果:" << output.trimmed();

        return sortedList;
    }


};

#endif // TOOL_HPP

